/**
 * XQuery to Scala Translator
 * Fatemeh Borran-Dejnabadi
 * 26 December 2004
 */

package xquery2src;

import java.io.{File,
                FileInputStream,
                FilenameFilter,
                FileOutputStream,
                IOException,
                InputStream,
                PrintWriter }

/** A small test class for the translator of xquey;
 *  @author buraq
 *  @todo: move error message outta here, maybe message format
 *  usage: scala xquery2src.Main (-d outdir)? file.xq file.xq*
 */
object Main  {

  final val SEP = java.io.File.separatorChar;

  var destdirF: File = null;
  var destdir: String = null;
  var inputfiles: List[String] = Nil;

  var failed = false;


  def isDir(descr:String, s:String): File = {
    val file = new java.io.File(s);
    if (!file.exists()) {
        fail(descr+" dir "+destdir+" does not exists");
        null
      } else if(!file.isDirectory()) {
        fail(descr+" dir "+destdir+" is not a directory");
        null
      } else file
  }

  def handleArgs(zs:Seq[String]): Unit = zs match {
    case Seq("-d", outdir, rest@_*) =>
      this.destdir = outdir;
      destdirF = new java.io.File(destdir);
      handleArgs(rest);
    case Seq("-in", infiles, rest@_*) =>
      val f = isDir("input", infiles);
      val files = f.listFiles(new FilenameFilter() {
        def accept(dir:File, name:String) = name.endsWith(".xq");
      });
      val i = Iterator.fromArray[File](files);
      this.inputfiles = this.inputfiles ::: i.toList.map{ x => x.toString() };
      handleArgs(rest);

    case Seq(files@_*) =>
      this.inputfiles = this.inputfiles ::: files.toList;
  }

  def fail(msg:String) = {
    Console.println(msg);
    this.failed = true;
  }

  def appendDestDir(sb:StringBuffer) = 
    if(null != destdir) {
      sb.append(destdir);
      sb.append(SEP);
    }
  
  def showDest(sb:StringBuffer) = {
    val sb = new StringBuffer();
    appendDestDir(sb);
    if( 0 < sb.length() )
      sb.append(':');
  }

  def main(args:Array[String]) = {
    handleArgs(args);

    if(destdir!=null)
      destdirF = isDir("output",destdir);

    if(0 == inputfiles.length) {
      fail("gimme input file");
    } 

    if(!failed)
      work();
  }

  def logTranslation(in:String, out:String) = {
    val sb = new StringBuffer();
    sb.append("translating file ");
    sb.append(in);
    sb.append(" to ");
    showDest(sb);
    sb.append(out);
    sb.append("...");
    Console.print(sb.toString());
 }

  def outfileName(i:String) = {
    val sb = new StringBuffer();
    appendDestDir(sb);
    val offset = 
      if(0 == sb.length()) 
        0 // retain full path
      else
        i.lastIndexOf(SEP)+1;

    sb.append(i.substring(offset, i.length() - 3));
    sb.toString(); 
  }

  def work() = {
    var translated = 0;
    var ignored = 0;
    def check(s:String): Boolean = {
      val ok = s.endsWith(".xq");
      if(!ok) {
        ignored = ignored + 1;
        Console.println("ignoring "+s+" cause it does not end in .xq");
      }
      ok
    }
    for(val i <- inputfiles.toList; check(i))  try {
      val outname = outfileName(i);
      val outf = outname +".scala";
      val objname = {
        val sb = new StringBuffer();
        val z:Seq[Char] = outname;
        val it = z.elements; while(it.hasNext) it.next match {
          case '/' | '\\' | '.' | ' ' => sb.append('_')
          case c                      => sb.append(c)
        }
        sb.toString()
      }
      logTranslation(i,outf);
      trait RunIt {
        def run():Unit
      }
      val trtor = new Translator() with RunIt {
        def run() = {
          val out = new PrintWriter(new FileOutputStream(outf));
          this.in  = new FileInputStream(i);
          nextCh();
          nextToken();
          val tree:Tree = parse();
          close();
          analyze(tree);
          tree.translation.append("package result;\n\n");
          tree.translation.append("import scala.xml._;\n");
          tree.translation.append("import xquery2src.Lib._;\n\n");
          tree.translation.append("object " + objname + " extends Application {\n");
          tree.translation.append("   val result = ");
          translate(tree);
          tree.translation.append(";\n   Console.println(result);\n}\n");
          out.write(tree.translation.toString());
          out.flush();
          out.close();
        }
      }
      trtor.run();
      Console.println("ok");
    } catch {
      case e:IOException =>
	Report.fail(e.getMessage());
    }
  if(0 < translated) Console.println("translated "+translated+" files");
  if(0 < ignored)    Console.println("ignored "+ignored+" files");
  }

}
